<template>
  <a-flex vertical="true" gap="small">
    <a-flex>
      <a-flex vertical="true" class="cronToolLeftBox">
        <a-menu v-model:selectedKeys="selectedKeys" mode="horizontal">
          <a-menu-item v-for="(field, key) in fields" :key="key">
            {{ field.label }}
          </a-menu-item>
        </a-menu>
        <a-card :bordered="false" style="height: 100%">
          <a-form :model="form" layout="vertical">
            <template v-for="(field, key) in fields" :key="key">
              <a-form-item v-if="selectedKeys.includes(key)">
                <a-radio-group
                  v-model:value="form[`${key}Type`]"
                  @change="updateField(key)"
                  style="display: block"
                >
                  <a-radio value="every" style="display: block; margin-bottom: 8px"
                    >每{{ field.label }}
                  </a-radio>
                  <a-radio value="range" style="display: block; margin-bottom: 8px"
                    >周期从
                    <a-input-number
                      v-model:value="form[`${key}RangeStart`]"
                      :min="field.min"
                      :max="field.max"
                      @change="updateField(key)"
                    />
                    {{ field.label }}到
                    <a-input-number
                      v-model:value="form[`${key}RangeEnd`]"
                      :min="field.min"
                      :max="field.max"
                      @change="updateField(key)"
                    />
                    {{ field.label }}
                  </a-radio>
                  <a-radio value="start" style="display: block; margin-bottom: 8px"
                    >周期从
                    <a-input-number
                      v-model:value="form[`${key}Start`]"
                      :min="field.min"
                      :max="field.max"
                      @change="updateField(key)"
                    />
                    {{ field.label }}开始每
                    <a-input-number
                      v-model:value="form[`${key}Interval`]"
                      :min="1"
                      :max="field.max"
                      @change="updateField(key)"
                    />
                    {{ field.label }}执行一次
                  </a-radio>
                  <a-radio value="specific" style="display: block; margin-bottom: 8px"
                    >指定某{{ field.label }}
                  </a-radio>
                </a-radio-group>
                <div style="margin-top: 10px; display: flex; flex-wrap: wrap">
                  <div v-for="(option, index) in field.options" :key="index" class="checkbox-item">
                    <a-checkbox
                      :value="option.value"
                      :checked="form[`${key}Specific`].includes(option.value)"
                      @change="(e) => handleCheckboxChange(e, key, option.value)"
                      :disabled="form[`${key}Type`] !== 'specific'"
                    >
                      {{ option.label }}
                    </a-checkbox>
                  </div>
                </div>
              </a-form-item>
            </template>
          </a-form>
        </a-card>
      </a-flex>
      <a-flex flex="1">
        <a-card :bordered="false" style="width: 100%">
          <a-form-item label="Cron 表达式">
            <a-input v-model:value="cronExpression" placeholder="" @change="parseCron" />
          </a-form-item>
          <h2>预计运行时间</h2>
          <div class="execution-cards-container">
            <div v-for="(item, index) in nextExecutionTimes" :key="index" class="execution-card">
              <div class="card-content">
                <span class="execution-time-text">执行时间 {{ index + 1 }}:</span>
                <span class="execution-time">{{ item }}</span>
              </div>
            </div>
          </div>
        </a-card>
      </a-flex>
    </a-flex>
    <a-flex vertical="true" flex="1" class="cronToolBottom">
      <a-card
        title="Cron表达式是一种用于指定定时任务执行时间的字符串表达式.它由分别表示秒、分钟、小时、天数、月份和星期几组成.每个字段指定时间范围或间隔"
        style="width: 100%"
      >
        <a-flex gap="small">
          <div class="cronToolLeftBox">
            <h4 class="leftBorderColor">特殊符号说明</h4>
            <ul>
              <li>星号（*）：表示匹配任意值。例如，* 在分钟字段中表示每分钟都执行。</li>
              <li>
                逗号（,）：用于分隔多个值。例如，1,3,5 在小时字段中表示 1 点、3 点和 5 点执行。
              </li>
              <li>斜线（/）：用于指定间隔值。例如，*/5 在分钟字段中表示每 5 分钟执行一次。</li>
              <li>连字符（-）：用于指定范围。例如，10-20 在日期字段中表示从 10 号到 20 号。</li>
              <li>问号（?）：仅用于日期和星期几字段，表示不指定具体值。通常用于避免冲突。</li>
            </ul>
          </div>
          <div>
            <h4 class="leftBorderColor">常用示例</h4>
            <ul>
              <li>0 0 12 * * ?：每天中午 12 点执行。</li>
              <li>0 0/5 * * * ?：每 5 分钟执行一次。</li>
              <li>0 0 8-18 ? * MON-FRI：周一至周五的 8 点到 18 点之间每小时执行一次。</li>
            </ul>
          </div>
        </a-flex>
      </a-card>
    </a-flex>
  </a-flex>
</template>

<script>
import { defineComponent, onMounted, reactive, ref, watch } from 'vue'
import CronParser from 'cron-parser'

export default defineComponent({
  setup() {
    const form = reactive({
      secondsType: 'every',
      secondsRangeStart: 0,
      secondsRangeEnd: 59,
      secondsStart: 0,
      secondsInterval: 1,
      secondsSpecific: [],
      minutesType: 'every',
      minutesRangeStart: 0,
      minutesRangeEnd: 59,
      minutesStart: 0,
      minutesInterval: 1,
      minutesSpecific: [],
      hoursType: 'every',
      hoursRangeStart: 0,
      hoursRangeEnd: 23,
      hoursStart: 0,
      hoursInterval: 1,
      hoursSpecific: [],
      dayOfMonthType: 'every',
      dayOfMonthRangeStart: 1,
      dayOfMonthRangeEnd: 31,
      dayOfMonthStart: 1,
      dayOfMonthInterval: 1,
      dayOfMonthSpecific: [],
      monthType: 'every',
      monthRangeStart: 1,
      monthRangeEnd: 12,
      monthStart: 1,
      monthInterval: 1,
      monthSpecific: [],
      yearType: 'every',
      yearRangeStart: 2025,
      yearRangeEnd: 2050,
      yearStart: 2025,
      yearInterval: 1,
      yearSpecific: [],
      // 新增周相关字段
      weekType: 'every',
      weekRangeStart: 1,
      weekRangeEnd: 53,
      weekStart: 1,
      weekInterval: 1,
      weekSpecific: []
    })

    const cronExpression = ref('* * * * * *')
    const selectedKeys = ref(['seconds'])
    const nextExecutionTimes = ref([])

    // 动态生成字段配置
    const fields = {
      seconds: {
        label: '秒',
        min: 0,
        max: 59,
        columns: 10,
        options: Array.from({ length: 60 }, (_, i) => ({ label: i, value: i }))
      },
      minutes: {
        label: '分钟',
        min: 0,
        max: 59,
        columns: 10,
        options: Array.from({ length: 60 }, (_, i) => ({ label: i, value: i }))
      },
      hours: {
        label: '小时',
        min: 0,
        max: 23,
        columns: 10,
        options: Array.from({ length: 24 }, (_, i) => ({ label: i, value: i }))
      },
      dayOfMonth: {
        label: '日',
        min: 1,
        max: 31,
        columns: 10,
        options: Array.from({ length: 31 }, (_, i) => ({ label: i + 1, value: i + 1 }))
      },
      month: {
        label: '月',
        min: 1,
        max: 12,
        columns: 10,
        options: Array.from({ length: 12 }, (_, i) => ({ label: i + 1, value: i + 1 }))
      },
      week: {
        label: '周',
        min: 1,
        max: 7,
        columns: 10,
        options: Array.from({ length: 7 }, (_, i) => ({ label: i + 1, value: i + 1 }))
      }
    }

    // 通用更新方法
    const updateField = (key) => {
      const type = form[`${key}Type`]
      let value = '*'
      switch (type) {
        case 'range':
          value = `${form[`${key}RangeStart`]}-${form[`${key}RangeEnd`]}`
          break
        case 'start':
          value = `${form[`${key}Start`]}/${form[`${key}Interval`]}`
          break
        case 'specific':
          value = form[`${key}Specific`].join(',')
          if (form[`${key}Specific`].length === 0 && fields[key].options.length > 0) {
            const optionsValue = fields[key].options[0].value
            form[`${key}Specific`].push(optionsValue)
            value = optionsValue
          }
          break
      }
      form[key] = value
      generateCron()
    }

    // 处理复选框变化的方法
    const handleCheckboxChange = (e, key, value) => {
      if (form[`${key}Type`] !== 'specific') {
        return
      }
      const isChecked = e.target.checked
      const specificArray = form[`${key}Specific`]

      if (!isChecked && specificArray.length === 1) {
        e.preventDefault()
        console.warn('至少需要保留一个选中的复选框')
        return
      }

      if (isChecked) {
        specificArray.push(value)
      } else {
        const index = specificArray.indexOf(value)
        if (index > -1) {
          specificArray.splice(index, 1)
        }
      }
      updateField(key)
    }

    const generateCron = () => {
      let cronExpressionArray = cronExpression.value.split(' ')
      // 调整数组索引对应周字段
      const fieldKeys = Object.keys(fields)
      for (let index = 0; index < fieldKeys.length; index++) {
        if (fieldKeys[index] === selectedKeys.value[0]) {
          cronExpressionArray[index] = form[fieldKeys[index]]
          break
        }
      }
      // 补全cron表达式位数（周需要6位）
      while (cronExpressionArray.length < 6) cronExpressionArray.push('*')
      cronExpression.value = cronExpressionArray.join(' ')
      calculateNextExecutionTimes()
    }

    const calculateNextExecutionTimes = () => {
      try {
        const cronStr = cronExpression.value

        const now = new Date()
        const times = []
        for (let i = 0; i < 12; i++) {
          const options = { currentDate: now, strict: true }
          // 2. 使用正确的方法调用
          const iterator = CronParser.parse(cronStr, options)
          const nextTime = iterator.next(now).toDate()
          times.push(nextTime.toLocaleString())

          now.setTime(nextTime.getTime() + 1)
        }
        nextExecutionTimes.value = times
      } catch (e) {
        console.log(e)
        nextExecutionTimes.value = ['无效的cron']
      }
    }

    onMounted(() => {
      calculateNextExecutionTimes()
    })

    const parseCron = () => {
      const parts = cronExpression.value.split(' ')
      if (parts.length === 6) {
        Object.keys(fields).forEach((key, index) => {
          form[key] = parts[index]
          const type = form[`${key}Type`]
          if (form[key] === '*') {
            form[`${key}Type`] = 'every'
          } else if (form[key].includes('-')) {
            form[`${key}Type`] = 'range'
            const [start, end] = form[key].split('-')
            form[`${key}RangeStart`] = parseInt(start)
            form[`${key}RangeEnd`] = parseInt(end)
          } else if (form[key].includes('/')) {
            form[`${key}Type`] = 'start'
            const [start, interval] = form[key].split('/')
            form[`${key}Start`] = parseInt(start)
            form[`${key}Interval`] = parseInt(interval)
          } else {
            form[`${key}Type`] = 'specific'
            form[`${key}Specific`] = form[key].split(',').map(Number)
          }
        })
      }
    }

    watch(form, generateCron, { deep: true })

    return {
      form,
      cronExpression,
      selectedKeys,
      fields,
      updateField,
      parseCron,
      handleCheckboxChange,
      nextExecutionTimes
    }
  }
})
</script>

<style scoped>
.checkbox-item {
  display: inline-flex;
  align-items: center;
  width: 10%;
  padding: 5px;
}

.cronToolLeftBox {
  width: 620px;
}

.execution-cards-container {
  display: flex;
  flex-wrap: wrap;
  gap: 18px;
  margin-top: 20px;
}

.execution-card {
  background: #fff;
  border-radius: 1px;
  padding: 5px;
  width: 30%;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  transition: all 0.2s;
}

.execution-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
}

.execution-time-text {
  color: #2b2c29;
  font-weight: 500;
  display: block;
  margin-bottom: 4px;
}

.cronToolBottom {
  height: 220px;
}

.execution-time {
  color: #1b6ee3;
  font-size: 14px;
  font-weight: 600;
}

.leftBorderColor {
  border-left: 4px solid #1b6ee3;
  padding-left: 8px;
}

.ant-card :deep(.ant-card-body) {
  padding-bottom: 0 !important;
  border-radius: 0 !important;
}

.ant-card :deep() {
  padding-bottom: 0 !important;
  border-radius: 0 !important;
}

</style>
